home *** CD-ROM | disk | FTP | other *** search
/ Aminet 44 / Aminet 44 (2001)(GTI - Schatztruhe)[!][Aug 2001].iso / Aminet / dev / misc / AmigaSDLsrc.lha / amisrc / SDL_timer.c < prev    next >
C/C++ Source or Header  |  2001-04-29  |  7KB  |  287 lines

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998  Sam Lantinga
  4.  
  5.     This library is free software; you can redistribute it and/or
  6.     modify it under the terms of the GNU Library General Public
  7.     License as published by the Free Software Foundation; either
  8.     version 2 of the License, or (at your option) any later version.
  9.  
  10.     This library is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.     Library General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU Library General Public
  16.     License along with this library; if not, write to the Free
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     Sam Lantinga
  20.     5635-34 Springhouse Dr.
  21.     Pleasanton, CA 94588 (USA)
  22.     slouken@devolution.com
  23. */
  24.  
  25. #ifdef SAVE_RCSID
  26. static char rcsid =
  27.  "@(#) $Id: SDL_timer.c,v 1.1.2.18 2001/02/13 10:05:49 hercules Exp $";
  28. #endif
  29.  
  30. #include <stdlib.h>
  31. #include <stdio.h>            /* For the definition of NULL */
  32.  
  33. #include "SDL_error.h"
  34. #include "SDL_timer.h"
  35. #include "SDL_timer_c.h"
  36. #include "SDL_mutex.h"
  37. #include "SDL_systimer.h"
  38.  
  39. /* #define DEBUG_TIMERS */
  40.  
  41. int SDL_timer_started = 0;
  42. int SDL_timer_running = 0;
  43.  
  44. /* Data to handle a single periodic alarm */
  45. Uint32 SDL_alarm_interval = 0;
  46. SDL_TimerCallback SDL_alarm_callback;
  47.  
  48. static SDL_bool list_changed = SDL_FALSE;
  49.  
  50. /* Data used for a thread-based timer */
  51. static int SDL_timer_threaded = 0;
  52.  
  53. struct _SDL_TimerID {
  54.     Uint32 interval;
  55.     SDL_NewTimerCallback cb;
  56.     void *param;
  57.     Uint32 last_alarm;
  58.     struct _SDL_TimerID *next;
  59. };
  60.  
  61. static SDL_TimerID SDL_timers = NULL;
  62. static Uint32 num_timers = 0;
  63. static SDL_mutex *SDL_timer_mutex;
  64.  
  65. /* Set whether or not the timer should use a thread.
  66.    This should not be called while the timer subsystem is running.
  67. */
  68. int SDL_SetTimerThreaded(int value)
  69. {
  70.     int retval;
  71.  
  72.     if ( SDL_timer_started ) {
  73.         SDL_SetError("Timer already initialized");
  74.         retval = -1;
  75.     } else {
  76.         retval = 0;
  77.         SDL_timer_threaded = value;
  78.     }
  79.     return retval;
  80. }
  81.  
  82. int SDL_TimerInit(void)
  83. {
  84.     int retval;
  85.  
  86.     SDL_timer_running = 0;
  87.     SDL_SetTimer(0, NULL);
  88.     retval = 0;
  89.     if ( ! SDL_timer_threaded ) {
  90.         retval = SDL_SYS_TimerInit();
  91.     }
  92.     if ( SDL_timer_threaded ) {
  93.         SDL_timer_mutex = SDL_CreateMutex();
  94.     }
  95.     SDL_timer_started = 1;
  96.     return(retval);
  97. }
  98.  
  99. void SDL_TimerQuit(void)
  100. {
  101.     SDL_SetTimer(0, NULL);
  102.     if ( SDL_timer_threaded < 2 ) {
  103.         SDL_SYS_TimerQuit();
  104.     }
  105.     if ( SDL_timer_threaded ) {
  106.         SDL_DestroyMutex(SDL_timer_mutex);
  107.     }
  108.     SDL_timer_started = 0;
  109.     SDL_timer_threaded = 0;
  110. }
  111.  
  112. void SDL_ThreadedTimerCheck(void)
  113. {
  114.     Uint32 now, ms;
  115.     SDL_TimerID t, prev, next;
  116.     int removed;
  117.  
  118.     now = SDL_GetTicks();
  119.  
  120.     SDL_mutexP(SDL_timer_mutex);
  121.     for ( prev = NULL, t = SDL_timers; t; t = next ) {
  122.         removed = 0;
  123.         ms = t->interval - SDL_TIMESLICE;
  124.         next = t->next;
  125.         if ( (t->last_alarm < now) && ((now - t->last_alarm) > ms) ) {
  126.             if ( (now - t->last_alarm) < t->interval ) {
  127.                 t->last_alarm += t->interval;
  128.             } else {
  129.                 t->last_alarm = now;
  130.             }
  131.             list_changed = SDL_FALSE;
  132. #ifdef DEBUG_TIMERS
  133.             printf("Executing timer %p (thread = %d)\n",
  134.                         t, SDL_ThreadID());
  135. #endif
  136.             SDL_mutexV(SDL_timer_mutex);
  137.             ms = t->cb(t->interval, t->param);
  138.             SDL_mutexP(SDL_timer_mutex);
  139.             if ( list_changed ) {
  140.                 /* Abort, list of timers has been modified */
  141.                 break;
  142.             }
  143.             if ( ms != t->interval ) {
  144.                 if ( ms ) {
  145.                     t->interval = ROUND_RESOLUTION(ms);
  146.                 } else { /* Remove the timer from the linked list */
  147. #ifdef DEBUG_TIMERS
  148.                     printf("SDL: Removing timer %p\n", t);
  149. #endif
  150.                     if ( prev ) {
  151.                         prev->next = next;
  152.                     } else {
  153.                         SDL_timers = next;
  154.                     }
  155.                     free(t);
  156.                     -- num_timers;
  157.                     removed = 1;
  158.                 }
  159.             }
  160.         }
  161.         /* Don't update prev if the timer has disappeared */
  162.         if ( ! removed ) {
  163.             prev = t;
  164.         }
  165.     }
  166.     SDL_mutexV(SDL_timer_mutex);
  167. }
  168.  
  169. SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param)
  170. {
  171.     SDL_TimerID t;
  172.     if ( ! SDL_timer_mutex ) {
  173.         if ( SDL_timer_started ) {
  174.             SDL_SetError("This platform doesn't support multiple timers");
  175.         } else {
  176.             SDL_SetError("You must call SDL_Init(SDL_INIT_TIMER) first");
  177.         }
  178.         return NULL;
  179.     }
  180.     if ( ! SDL_timer_threaded ) {
  181.         SDL_SetError("Multiple timers require threaded events!");
  182.         return NULL;
  183.     }
  184.     SDL_mutexP(SDL_timer_mutex);
  185.     t = (SDL_TimerID) malloc(sizeof(struct _SDL_TimerID));
  186.     if ( t ) {
  187.         t->interval = ROUND_RESOLUTION(interval);
  188.         t->cb = callback;
  189.         t->param = param;
  190.         t->last_alarm = SDL_GetTicks();
  191.         t->next = SDL_timers;
  192.         SDL_timers = t;
  193.         ++ num_timers;
  194.         list_changed = SDL_TRUE;
  195.         SDL_timer_running = 1;
  196.     }
  197. #ifdef DEBUG_TIMERS
  198.     printf("SDL_AddTimer(%d) = %08x num_timers = %d\n", interval, (Uint32)t, num_timers);
  199. #endif
  200.     SDL_mutexV(SDL_timer_mutex);
  201.     return t;
  202. }
  203.  
  204. SDL_bool SDL_RemoveTimer(SDL_TimerID id)
  205. {
  206.     SDL_TimerID t, prev = NULL;
  207.     SDL_bool removed;
  208.  
  209.     removed = SDL_FALSE;
  210.     SDL_mutexP(SDL_timer_mutex);
  211.     /* Look for id in the linked list of timers */
  212.     for (t = SDL_timers; t; prev=t, t = t->next ) {
  213.         if ( t == id ) {
  214.             if(prev) {
  215.                 prev->next = t->next;
  216.             } else {
  217.                 SDL_timers = t->next;
  218.             }
  219.             free(t);
  220.             -- num_timers;
  221.             removed = SDL_TRUE;
  222.             list_changed = SDL_TRUE;
  223.             break;
  224.         }
  225.     }
  226. #ifdef DEBUG_TIMERS
  227.     printf("SDL_RemoveTimer(%08x) = %d num_timers = %d thread = %d\n", (Uint32)id, removed, num_timers, SDL_ThreadID());
  228. #endif
  229.     SDL_mutexV(SDL_timer_mutex);
  230.     return removed;
  231. }
  232.  
  233. static void SDL_RemoveAllTimers(SDL_TimerID t)
  234. {
  235.     SDL_TimerID freeme;
  236.  
  237.     /* Changed to non-recursive implementation.
  238.        The recursive implementation is elegant, but subject to 
  239.        stack overflow if there are lots and lots of timers.
  240.      */
  241.     while ( t ) {
  242.         freeme = t;
  243.         t = t->next;
  244.         free(freeme);
  245.     }
  246. }
  247.  
  248. /* Old style callback functions are wrapped through this */
  249. static Uint32 callback_wrapper(Uint32 ms, void *param)
  250. {
  251.     SDL_TimerCallback func = (SDL_TimerCallback) param;
  252.     return (*func)(ms);
  253. }
  254.  
  255. int SDL_SetTimer(Uint32 ms, SDL_TimerCallback callback)
  256. {
  257.     int retval;
  258.  
  259. #ifdef DEBUG_TIMERS
  260.     printf("SDL_SetTimer(%d)\n", ms);
  261. #endif
  262.     retval = 0;
  263.     if ( SDL_timer_running ) {    /* Stop any currently running timer */
  264.         SDL_timer_running = 0;
  265.         if ( SDL_timer_threaded ) {
  266.             SDL_mutexP(SDL_timer_mutex);
  267.             SDL_RemoveAllTimers(SDL_timers);
  268.             SDL_timers = NULL;
  269.             SDL_mutexV(SDL_timer_mutex);
  270.         } else {
  271.             SDL_SYS_StopTimer();
  272.         }
  273.     }
  274.     if ( ms ) {
  275.         if ( SDL_timer_threaded ) {
  276.             retval = (SDL_AddTimer(ms, callback_wrapper,
  277.                            (void *)callback) != NULL);
  278.         } else {
  279.             SDL_timer_running = 1;
  280.             SDL_alarm_interval = ms;
  281.             SDL_alarm_callback = callback;
  282.             retval = SDL_SYS_StartTimer();
  283.         }
  284.     }
  285.     return retval;
  286. }
  287.